package EA;
import EA.Framework;
import RKUjava.util.RKUStringUtils;
import RKUjava.util.*;

/** Abstract class for numerical optimization EA's */
public class NumericalGenome extends Genome
{
  /** If realposcalculated is true, then realpos contains the values of the
      genomes current state. */
  public double[] realpos;

  /** Indicates whether or not the realpos array contains latest values.
      Call updatePos() to recalculate realpos.
  */
  public boolean realposcalculated;

  /** Create a new numerical genome. 
      @param frame The framework for the EA this genome is a part of. 
      This must be a subclass of NumericalFramework.
  */
  public NumericalGenome(Framework frame)
    {
      super(frame);
      realpos = new double[((NumericalFramework)frame).dimensions];
      realposcalculated = false;

    }

  /** Set position in the searchspace. This method will copy the given
      pos to the internal realpos. When the copying is performed it calls
      NumericalGenome_setPos_inner().
  */
  public void setPos(double[] pos)
    {
      for (int i=0;i<realpos.length;i++) {
	realpos[i] = pos[i];
      }
      NumericalGenome_setPos_inner();
      realposcalculated = true;
      fitnesscalculated = false;
    }

  /** Set position in the searchspace. This method overwrite the
      internal realpos with the given pos. Then
      NumericalGenome_setPos_inner() is called to allow updating of
      internal structures (e.g. binary representation).  */
  public void setPosReference(double[] pos)
    {
      realpos = pos;

      NumericalGenome_setPos_inner();
      realposcalculated = true;
      fitnesscalculated = false;
    }

  /** BETA style inner call for setPos().<br>
      Override this method when subclassing.
  */
  public void NumericalGenome_setPos_inner()
    {
    };

  /** Get position in the searchspace. 
   @return A copy of the internal position. 
*/
  public double[] getPos()
    {
      updatePos();
      return RKUArrays.cloneArray(realpos);
    }

  /** Get the reference to the position in the searchspace.
      @return The array pointer of the internal position. 
  */
  public double[] getPosReference()
    {
      updatePos();
      return realpos;
    }

  /** Get value of specific coordinate of the current position. */
  public double getCoordinateValue(int i)
    {
      updatePos();
      return realpos[i];
    }
  /** Update the realpos vector. This method calls the 
      NumericalGenome_updatePos_inner() method, which must be overridden in
      subclasses. 
  */
  public void updatePos()
    {
      if (!realposcalculated) {
	NumericalGenome_updatePos_inner();
	realposcalculated = true;
      }
    }

  /** Get the number of dimensions for this numerical genome. */
  public int getDimensions()
    {
      return realpos.length;
    }

  /** BETA style inner call for updatePos().<br>
      Override this method when subclassing. It must fill the realpos array
      with the real values corresponding to the subclass' genome encoding.
      E.g. if you have subclassed to a bitencoding version, then this method 
      must convert/calculate the corresponding real values from the bits.
  */
  public void NumericalGenome_updatePos_inner()
    {
    };

  /** Calculate fitness of genome. This is done by calling calcFitness 
   in the NumericalFramework. <br>
   No need to override this. It calls updatePos()
   and the it set the fitness field by calling the calcFitness of the 
   NumericalFramework class.
   */
  public void Genome_getFitness_inner()
    {
      updatePos();
      if (framework!=null)
	fitness = ((NumericalFitness)framework.fitnessfunction).calcFitness(realpos);
      else
	fitness = 0;
    }

  /** Perform a crossover between genome1 and genome2. */
  public static Genome crossover(Genome genome1, Genome genome2)
    {
      return null;
    }

  public String toString()
    {
      updatePos();
      return RKUStringUtils.arrayToString(realpos);
    }

  public String shortToString()
    {
      updatePos();
      return RKUStringUtils.arrayToString(realpos);
    }

}
